#include "./ble_task.h"
#include "../driver/ble_uart.h"
#include <string.h>
#include "../utils/decode.h"
#include "./handler_task.h"
#include "../driver/sensor.h"

namespace task {

using namespace driver;

static constexpr uint32_t PkgNext = static_cast<uint32_t>(-1);
using namespace utils;

void BLETask::run() {

    utils::byte_view_t bw;

    while (true) {
        osStatus_t ret = bleUart->poll(bw);
        if (ret != osOK) {
            continue;
        }
        uint32_t index = 0;
        while (index < bw.len) {
            uint32_t ret = pkg_exec(bw.buf + index, bw.len - index);
            if (ret == PkgNext) {
                break;
            }
            index += ret;
        }
    }
}

void BLETask::post(const uint8_t *buf, uint32_t len) {
    uint8_t s = utils::alg::sun_xor(buf + 6, len - 8);
    if (s != buf[len - 2]) {
        return;
    }
    if (utils::proto::End != buf[len - 1]) {
        return;
    }
    if (!sensor->is_door_open()) {
        return;
    }
    bleUart->write(proto::Ack);
    message_t msg(buf, len, message_t::Uart::BLE);
    handlerTask->post(msg);
}

uint32_t BLETask::pkg_exec(const uint8_t *buf, uint32_t len) {

    if (!m_head_flag) {
        if (len < 8) {
            return PkgNext;
        }
        uint16_t head = decode_uint16(buf);
        if (head != proto::Head) {
            return PkgNext;
        }
        uint16_t size = decode_uint16(buf + 2);
        if ((size < 8) || (size > RecvBuffSize)) {
            return PkgNext;
        }
        m_pkg_index = 0;
        m_pkg_len = size;
        m_head_flag = true;
    }

    uint32_t n = m_pkg_len - m_pkg_index;
    if (n > len) {
        n = len;
    }
    memcpy(m_recv_buf + m_pkg_index, buf, n);
    m_pkg_index += n;

    if (m_pkg_index == m_pkg_len) {
        post(m_recv_buf, m_pkg_len);
        m_head_flag = false;
    }

    return n;
}

}
